import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { AppAxiosConfig } from './types'
/**
 * 两个重点
 * 1. 拦截器进行精准控制
 *    >全局拦截器
 *    >实例拦截器
 *    >单次请求拦截
 * 2. 响应结果的类型处理<泛型>
 */

class AppAxios {
  // axios 实例
  private instance: AxiosInstance

  constructor(config: AppAxiosConfig) {
    // 初始化实例
    this.instance = axios.create(config)
    // 每个instance实例都添加拦截器
    // 拦截器的执行顺序为：类请求→实例请求→实例响应→类响应；这样我们就可以在实例拦截上做出一些不同的拦截
    // 全局请求拦截
    this.instance.interceptors.request.use(
      (req) => {
        return req
      },
      (err) => {
        return err
      }
    )
    // 全局响应拦截器保证最后执行
    this.instance.interceptors.response.use(
      (res) => {
        return res.data
      },
      (err) => {
        const { response } = err
        // console.log(response.status)
        return err
      }
    )
    // 针对特定效果的AppRequest实例添加拦截器
    // 请求拦截
    this.instance.interceptors.request.use(
      config.interceptors?.requestInterceptors,
      config.interceptors?.requestInterceptorsCatch
    )
    this.instance.interceptors.response.use(
      config.interceptors?.responseInterceptors,
      config.interceptors?.responseInterceptorsCatch
    )
  }
  // 封装网络请求的方法
  request<T = any>(config: AppAxiosConfig<T>): Promise<T> {
    // 单次请求的成功拦截处理
    if (config.interceptors?.requestInterceptors) {
      config = config.interceptors.requestInterceptors(config)
    }
    // 返回Promise
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          // 单次响应的成功拦截器
          if (config.interceptors?.responseInterceptors) {
            res = config.interceptors.responseInterceptors(res)
          }
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }
  get<T = any>(config: AppAxiosConfig<T>) {
    return this.request({ ...config, method: 'GET' })
  }
  post<T = any>(config: AppAxiosConfig<T>) {
    return this.request({ ...config, method: 'POST' })
  }
  delete<T = any>(config: AppAxiosConfig<T>) {
    return this.request({ ...config, method: 'DELETE' })
  }
  patch<T = any>(config: AppAxiosConfig<T>) {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default AppAxios
